Skip to main content

Coding4 - 📘 User Authentication

🧠 What You’ll Learn

In this lesson, you’ll learn how to:

  • Create a User model
  • Secure passwords using hashing
  • Authenticate users with JSON Web Tokens (JWT)
  • Build signup, login, and logout routes

🛠️ Step 1: Install Required Packages

In your terminal, run:

npm install bcryptjs jsonwebtoken
npm install --save-dev @types/bcryptjs @types/jsonwebtoken

Why?

  • bcryptjs will hash passwords
  • jsonwebtoken will create and verify login tokens

🧱 Step 2: Create the User Model

File: src/model/user.model.ts

import mongoose, { Schema, Document } from 'mongoose';
import bcrypt from 'bcryptjs';

// User interface for TypeScript
export interface IUser extends Document {
name: string;
email: string;
password: string;
comparePassword: (inputPassword: string) => Promise<boolean>;
}

// Define the user schema
const UserSchema: Schema<IUser> = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});

// Automatically hash the password before saving
UserSchema.pre<IUser>('save', async function (next) {
if (!this.isModified('password')) return next(); // only hash if modified
this.password = await bcrypt.hash(this.password, 10); // hash the password
next();
});

// Method to compare plain password with hashed one
UserSchema.methods.comparePassword = async function (inputPassword: string) {
return bcrypt.compare(inputPassword, this.password);
};

export default mongoose.model<IUser>('User', UserSchema);

Explanation: This model defines how users are stored in the database and ensures passwords are securely hashed.


🔐 Step 3: Build the Authentication Controller

File: src/controller/auth.controller.ts

import { Request, Response } from 'express';
import User from '../model/user.model';
import jwt from 'jsonwebtoken';

// Function to create a JWT token
const generateToken = (id: string) => {
return jwt.sign({ id }, process.env.JWT_SECRET as string, {
expiresIn: '1d', // valid for 1 day
});
};

// User signup controller
export const signup = async (req: Request, res: Response) => {
const { name, email, password } = req.body;

try {
const existingUser = await User.findOne({ email });
if (existingUser)
return res.status(400).json({ message: 'User already exists' });

const user = await User.create({ name, email, password });
const token = generateToken(user._id.toString());

res.status(201).json({
token,
user: { id: user._id, name: user.name, email: user.email },
});
} catch (error) {
res.status(500).json({ message: 'Signup failed', error });
}
};

// User login controller
export const login = async (req: Request, res: Response) => {
const { email, password } = req.body;

try {
const user = await User.findOne({ email });

// Check if user exists and password is valid
if (!user || !(await user.comparePassword(password))) {
return res.status(401).json({ message: 'Invalid credentials' });
}

const token = generateToken(user._id.toString());

res.json({
token,
user: { id: user._id, name: user.name, email: user.email },
});
} catch (error) {
res.status(500).json({ message: 'Login failed', error });
}
};

// User logout controller (token stays on client)
export const logout = (_req: Request, res: Response) => {
res.json({ message: 'Logged out successfully (client should delete token)' });
};

Explanation: This handles:

  • 🔐 Signup: creates a new user and returns a token
  • 🔑 Login: verifies credentials and returns a token
  • 🚪 Logout: clears session (from client)

🛣️ Step 4: Create the Auth Routes

File: src/routes/auth.routes.ts

import { Router } from 'express';
import { signup, login, logout } from '../controller/auth.controller';

const router = Router();

router.post('/signup', signup); // register
router.post('/login', login); // login
router.get('/logout', logout); // logout

export default router;

Explanation: This connects the controller functions to actual URLs. Now you can use /api/auth/signup, etc.


🌐 Step 5: Use Routes in the App

File: src/app.ts

import express from 'express';
import dotenv from 'dotenv';
import connectDB from './dbconnect';
import authRoutes from './routes/auth.routes';

dotenv.config(); // load env variables

const app = express();
const PORT = process.env.PORT || 5000;

// Connect to MongoDB
connectDB(process.env.MONGO_URI as string);

// Middleware to parse JSON
app.use(express.json());

// Register our auth API routes
app.use('/api/auth', authRoutes);

app.get('/', (_req, res) => res.send('API is running...'));

app.listen(PORT, () => {
console.log(`🚀 Server running on port ${PORT}`);
});

Explanation: This is your main app file that starts the server and includes the routes for authentication.


🔑 Step 6: Add Environment Variables

File: .env

PORT=5000
MONGO_URI=mongodb://localhost:27017/your-db-name
JWT_SECRET=yourStrongSecretHere

Explanation: Keep sensitive data like database URI and secret keys out of your codebase.


✅ Final Result

Your auth routes are now live!

MethodEndpointWhat it does
POST/api/auth/signupRegister new user
POST/api/auth/loginLogin existing user
GET/api/auth/logoutLogout (client-side)